/**
 * Created by huangyuchen on 7/26/16.
 */

import {
  connectionDefinitions,
  cursorToOffset,
  offsetToCursor,
  connectionFromArraySlice,
} from 'graphql-relay';

import { GcArgumentsError } from '../errors';

const cache = {};

export const connectionFromType = (name, type) => {
  let definition;
  const identity = `${name}__${type.name}`;
  if (cache[identity]) {
    definition = cache[identity];
  } else {
    definition = connectionDefinitions({
      name,
      nodeType: type,
    });
    cache[identity] = definition;
  }
  return {
    connection: definition.connectionType,
    edge: definition.edgeType,
  };
};

export const connectionFromModel = async (model, options, args) => {
  const { first, last, before, after } = args;
  if ((first && last) || (first && before) || (after && before) || (after && last)) {
    throw new GcArgumentsError('connection参数错误');
  }
  const dataCount = await model.count(options);
  let offset = 0;
  let limit = dataCount;
  if (first) {
    limit = first;
    offset = after ? cursorToOffset(after) + 1 : 0;
  } else if (last) {
    limit = last;
    offset = before ? cursorToOffset(before) - last : dataCount - last;
  }
  if ((first && first <= 0) || (last && last <= 0)) {
    throw new GcArgumentsError('参数first/last必须大于0');
  }
  offset = offset > 0 ? offset : 0;
  offset = offset < dataCount ? offset : dataCount;
  const dataSet = await model.findAll(Object.assign(
    {
      order: ['id'],
    },
    options,
    {
      limit,
      offset,
    })
  );
  return {
    ...connectionFromArraySlice(dataSet, args, { sliceStart: offset, arrayLength: dataCount }),
    totalCount: dataCount,
  };
};

export const genMutationConnectionEdge = async (model, options, instanceId) => {
  const instance = await model.findById(instanceId);
  if (!instance) {
    return null;
  }
  const dataCount = await model.count(Object.assign(
    {
      order: ['id'],
    },
    options,
    {
      where: Object.assign({}, options.where, { id: { lt: instanceId } }),
    },
  ));
  return {
    cursor: offsetToCursor(dataCount),
    node: instance,
  };
};

export default {
  connectionFromType,
  connectionFromModel,
  genMutationConnectionEdge,
};
